#pragma once

#include "Arduino.h"
#include <inttypes.h>
#include <avr/pgmspace.h>
#include <HardwareSerial.h>
#include "RingBuffer.h"

#define MSG_BUFFER_MAX 128
#define CACHE_BUFF_MAX MSG_BUFFER_MAX * 2

struct WifiMessage {
    int  size;              // 长度
    char channel;           // 频道
    char* message;    // 数据
};

struct WifiConnection {
    char channel;       // 频道
    bool connected: 1;  // 已连接
    int trycount;      // 尝试次数
};

struct WifiSSID {
    const char* ssid;
    int rssi;
};

struct charFind {
    bool find: 1;
    int pos;
};

struct Flags { // 1 byte value (on a system where 8 bits is a byte
    bool started : 1,
         echoOnOff : 1,
         serverConfigured : 1,           // true if a connection to a remote server is configured
         apConfigured : 1,               // true if the module is configured as a client station
         localApConfigured : 1,
         localServerConfigured : 1,
         localApRunning : 1,
         localServerRunning : 1,
         endSendWithNewline : 1,
         connectToServerUsingTCP : 1;
};

class SerialESP8266wifi {
public:
    typedef void (*cmdDealFunc)(WifiMessage* msg);
public:
    SerialESP8266wifi(Stream& serialIn, Stream& serialOut, int resetPin);

    SerialESP8266wifi(Stream& serialIn, Stream& serialOut, int resetPin, Stream* dbgSerial);

    int begin();       // 开始

    bool isStarted();   // 是否已启动

    // 连接到路由器
    bool connectToAP(const String& ssid, const String& password);
    bool connectToAP(const char* ssid, const char* password);
    bool isConnectedToAP();

    void getIPMAC(char* ip, int maxip, int& lenip, char* mac, int mmac, int& lmac);
    int getSSIDs(WifiSSID* ssids, int slen, const char** names = nullptr, int nlen = 0);

    void watchdog();    // 监视连接状态
    void checkInput(bool log = false);  // 检查输入数据
    void registCall(cmdDealFunc func); // 注册消息回调

    void setTransportToUDP();   // udp数据传输
    void setTransportToTCP();   // tcp数据传输

    // 连接到服务器
    bool connectToServer(String& ip, String& port);
    bool connectToServer(const char* ip, const char* port);

    void disconnectFromServer();    // 断开连接
    bool isConnectedToServer();     // 是否连接服务器

    // 启动本地路由和服务
    bool startLocalAPAndServer(const char* ssid, const char* password, const char* channel, const char* port);
    // 启动本地路由
    bool startLocalAP(const char* ssid, const char* password, const char* channel);
    // 启动本地服务
    bool startLocalServer(const char* port);
    // 停止本地路由和服务
    bool stopLocalAPAndServer();
    // 停止本地路由
    bool stopLocalAP();
    // 停止本地服务
    bool stopLocalServer();
    // 是否本地路由和服务开启
    bool isLocalAPAndServerRunning();
    // 是否本地服务开启
    bool isLocalServerRunning();

    // 发送数据
    void send(char channel, String& message);
    void send(char channel, const char* message);

    // 分步发送数据
    bool startSend(char channel, int size);
    void addSend(char channel, const String& message);
    void endSend(char channel, const String& message);

    // 自动追加换行
    void endSendWithNewline(bool endSendWithNewline);

     // 检查buff
    bool checkBuffer(const char* in, const char* ckeck, int inlen = 0,
                     int cklen = 0, bool equal = true);

    // 打印日志
    void showLog(const String& info);
    // 打印字符
    void showChar(char c);
private:
    Stream* _serialIn;      // 输入串口
    Stream* _serialOut;     // 输出串口
    int _resetPin;          // 重置端口

    Flags flags;            // 运行标记

    bool connectToServer(); // 连接到服务器
    char _ip[16];
    char _port[6];

    bool connectToAP();     // 连接到路由器
    char _ssid[16];
    char _password[16];

    bool startLocalAp();    // 启动路由器
    bool startLocalServer();    // 启动本地服务
    char _localAPSSID[16];
    char _localAPPassword[16];
    char _localAPChannel[3];
    char _localServerPort[6];
    WifiConnection _connection;

    bool restart();         // 重新启动

    // 输出指令
    void writeCommand(const char* text1, const char* text2 = nullptr);
    // 读取指令
    int readCommand(int timeout, const char* text1, const char* text2 = nullptr,
                    bool log = false, bool clear = true);
    // 读取数据
    charFind readBuffer(int timeout, const char* key, char* data, int dlen,
                    char delim = 0, bool log = false);

    Stream* _dbgSerial;     // 日志调试串口

    RingBuffer  recvcache;  // 接收缓存
    char readcache[MSG_BUFFER_MAX]; // 读取缓存
    uint8_t     rdchpos;    // 读取缓存pos
    int         rdmsginc;   // 读取消息增量
    int         posipd;     // ipd标记
    int         ipdindex;   // ipd序号
    int         ipdsize;    // ipd长度
    cmdDealFunc callfunc;   // 消息回调
};

